import math
import random
import time

from django.conf import settings

from EE.models import Game
from EE.models import GameState
from EE.models import Island
from EE.models import Decision
from EE.models import StateMill
from EE.models import DecisionMill

from EE.logic import user_profile as user_profile_logic
from EE.logic import game as game_logic
from EE.logic import decision as decision_logic
from EE.logic import island as island_logic
from EE.logic import state_mill as state_mill_logic
from EE.logic import decision_mill as decision_mill_logic
from EE.logic import contract as contract_logic
from django.contrib.auth.models import User

def createNew(reference_user):
  gamestate = createNewRound(reference_user)
  contract = contract_logic.releaseFirst(reference_user)
  return gamestate
  
def createNewRound(reference_user):
  prof = user_profile_logic.getProfile(reference_user)
  game = prof.gamePlay.all().get()
  if game.turn >= 1:
    prev = GameState.objects.filter(user=reference_user).filter(round=game.turn-1).get()
  else:
    prev = GameState(user=reference_user, game=game, balance=500000000, debt=0, round=game.turn)  
  gamestate = GameState(user=reference_user, game=game, balance=prev.balance, debt=prev.debt, round=game.turn)
  gamestate.save()
  try:
    island = island_logic.getIsland(prev)
    island.state = gamestate
    island.save()
  except Island.DoesNotExist:
    island = island_logic.createNew(gamestate, 0, 0, 0)
  try:
    decision = decision_logic.getDecision(prev) #needed for decision_mill_logic.getDecisionMill
    gamestate.balance = decision.balance
    gamestate.debt = decision.debt
    gamestate.save()
    decision = decision_logic.createNew(gamestate, gamestate.balance, gamestate.debt)
  except Decision.DoesNotExist:
    decision = decision_logic.createNew(gamestate, gamestate.balance, gamestate.debt)
    prev = gamestate
  try:
    decision_mill = decision_mill_logic.getDecisionMill(decision_logic.getDecision(prev))
    arr = []
    for dm in decision_mill:
	  arr.append((dm.noOfMills, dm.noOfMills1Month, dm.noOfMills2Months, dm.noOfMills3Months, dm.noOfMaintenance, dm.noOfBrokenMills, dm.typeOfMill))
    decision_mill_new = decision_mill_logic.updateDecisionMills(decision, arr) #do not think I can guarentee this will work...
  except DecisionMill.DoesNotExist:
    mills = game_logic.getMills(game)
    arr = []
    for m in mills:
      arr.append((0, m))
    decision_mill = decision_mill_logic.createNew(decision, arr)
  try:
    state_mill = state_mill_logic.getStateMills(prev)
    for mill in state_mill:
	  state_mill_new = state_mill_logic.update(mill, gamestate)
  except StateMill.DoesNotExist:
    mills = game_logic.getMills(game)
    arr = []
    for m in mills:
	  arr.append((0, m))
    state_mill = state_mill_logic.createNew(gamestate, arr)
  if game.turn >= 1:
    decision_mill_logic.handle_breakdown_mills(decision, breakdown_windmill(gamestate))

  return gamestate
  
def handle_made_turn(size, mills, balance, debt, game_state, cost):
  gamestate = game_state
  old_balance = gamestate.balance
  old_debt = gamestate.debt
  if (gamestate.round == 0):
    try:
	  island = island_logic.getIsland(gamestate)
	  island.cost = cost
	  island.capacity = size
	  island.save()
    except Island.DoesNotExist:
	  island = island_logic.createNew(gamestate, cost, size, 0)
  else:
	island = island_logic.getIsland(gamestate)
  #gamestate.balance=balance
  #gamestate.debt=debt
  #gamestate.save()
  #island = Island.objects.filter(state=game_state).get()
  #island.cost=cost
  #island.capacity=size
  #island.save()
  
  #decision = decision_logic.handle_made_turn(gamestate, old_balance+balance, old_debt+debt)  
  decision = decision_logic.handle_made_turn(gamestate, balance, debt) 
  if gamestate.round == 0:  
    state_mill = state_mill_logic.handle_made_turn(gamestate, mills)
  decision_mill = decision_mill_logic.handle_made_turn(decision, mills)
    
  return [gamestate, island, decision]
  
def handle_end_round(reference_game):
  #reference_game has no updated turn number!
  for u in game_logic.getPlayers(reference_game):
    not_delivered = month_output(u)
    delivered = (contract_logic.get_total_usage(u)*28) - not_delivered
	
    ##print 'verplichtingen: '+ str(contract_logic.get_total_usage(u)*28)
    ##print 'not delivered: '+ str(not_delivered)
    
    decision = decision_logic.getDecision(getState(u))
    balance = decision.balance
    debt = decision.debt
    reparatie_aantal = decision_mill_logic.getTotalNoOfBrokenMills(decision)
    
    balance = balance + (delivered * contract_logic.get_average_price(u))
    ##print 'winst: '+str(delivered * contract_logic.get_average_price(u))
    ##print 'delivered: '+str(delivered)
    ##print 'average price: '+str(contract_logic.get_average_price(u))
    balance = balance - (not_delivered * 50)
    #balance = balance - (debt * (0.08/12))
    balance = balance - (reparatie_aantal * 60000)
	
    if balance < 0:
      debt = debt - balance
    else:
      debt = debt + balance
    balance = 0	  
			
    decision.balance = balance
    decision.debt = debt
    decision.save()
    
    #do something with decisions and states here
    decision_logic.handle_end_round(getState(u))
    decision_mill_logic.handle_end_round(decision_logic.getDecision(getState(u)))
    contract_logic.handle_end_round(decision_logic.getDecision(getState(u)))
	#createNewRound(u)		
	
def create_new_states(reference_game):
  for u in game_logic.getPlayers(reference_game):
    #game number is updated now
	createNewRound(u)
  
def getState(reference_user):
  game = user_profile_logic.getProfile(reference_user).gamePlay.all().get()
  #filter on round ensures you always get the latest gamestate!
  gamestate = GameState.objects.filter(game=game).filter(user=reference_user).filter(round=game.turn).get()
  return gamestate
  
#Still need a function that returns all the gamestates, so we can do something with the history
  
def getIsland(reference_state):
  island = Island.objects.filter(state=reference_state).get()
  return island

def month_output(ref_user):    
    #Should all come from Database
	game = game_logic.getGame(ref_user)
	ref_state = getState(ref_user)
	island = island_logic.getIsland(ref_state)
	
	current_buffer = island.currentContent
	max_buffer = island.capacity
	capacity_lost = 0
	not_delivered = 0
	days_in_month = 28
	day_usage = contract_logic.get_total_usage(ref_user) # afhankelijk van contracten...

	storm = game.storm

	for i in range(1, days_in_month+1):
		day_surplus = 0
		day_output = 0
		windforce = generate_windforce()
		if (storm == True):
			windforce = windforce + 3
                    
		state_mills_for_game_state = StateMill.objects.filter(state=ref_state).select_related().all()
    
		for mill in state_mills_for_game_state:
			no_windmills = mill.noOfMills
			windmill = mill.typeOfMill
			capacity = windmill.capacity
			
			if (windforce == 3):
				day_output = day_output + (no_windmills * capacity * 0.2)
			elif (windforce == 4):
				day_output = day_output + (no_windmills * capacity * 0.4)
			elif (windforce == 5):
				day_output = day_output + (no_windmills * capacity * 0.6)
			elif (windforce == 6):
				day_output = day_output + (no_windmills * capacity * 0.8)
			elif (windforce == 7):
				day_output = day_output + (no_windmills * capacity * 0.9)
			elif (windforce == 8):
				day_output = day_output + (no_windmills * capacity)
			else:
				day_output = 0
				break
			
			time.sleep(0.1)
			
            
		day_surplus = (day_output * 24) - day_usage  

		##print 'day_surplus: '+str(day_surplus)
		##print 'day_surplus: '+str(day_surplus)
         
		if day_surplus > 0:
			current_buffer = current_buffer + day_surplus
			if current_buffer > max_buffer:
				capacity_lost = capacity_lost + (current_buffer - max_buffer)
				current_buffer = max_buffer
		elif day_surplus < 0:
			if (0.5 * current_buffer) > math.fabs(day_surplus):
				current_buffer = current_buffer - (2 * math.fabs(day_surplus))
			elif (0.5 * current_buffer) < math.fabs(day_surplus):
				not_delivered = not_delivered + (math.fabs(day_surplus) - (0.5 * current_buffer))
				current_buffer = 0
		time.sleep(0.1)
	
	island.currentContent = current_buffer
	island.save()
	return not_delivered
				
# Generating a windforce 
def generate_windforce():    
	random.seed(None)
	windforce = int(random.normalvariate(4,2))
	if windforce <= 0:
		windforce = 0
	elif windforce >= 8:
		windforce = 8
	return windforce
	
# How many windmills are breaking down       
def breakdown_windmill(ref_state):

	result = []
	
	state_mills_for_game_state = state_mill_logic.getStateMills(ref_state)
    
	for mill in state_mills_for_game_state:
		windmills_broken = 0
		
		no_windmills = mill.noOfMills         
    
        maintenance = mill.noOfMaintenance
        no_maintenance = no_windmills - maintenance
        
        for i in range(1, maintenance + 1):
            random.seed(None)
            chance = random.randint(0,100)
            if (chance > 95):
                windmills_broken = windmills_broken + 1
                #print 'Er is een windmolen met onderhoudscontract stuk'
    
        for u in range(1, no_maintenance +1):
            random.seed(None)
            chance = random.randint(0,100)
            if (chance > 90):
                windmills_broken = windmills_broken + 1
                #print 'Er is een windmolen zonder onderhoudscontract stuk'
		
		result.append((mill.typeOfMill, windmills_broken))
            
	return result